package com.stellar.wechat.config;

import com.stellar.wechat.core.storage.TokenStorage;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.concurrent.TimeUnit;

/**
 * @Author Jqcc
 * @Version 1.0
 * @Data 2025/3/29
 * @Description 微信配置
 */
@Configuration
@EnableConfigurationProperties // 启用配置属性绑定
public class WxConfiguration {

    /**
     * Redis 存储实现（生产环境使用）
     */
    @Bean
    @ConditionalOnProperty(name = "wx.mp.config-storage.type", havingValue = "redistemplate")
    public TokenStorage redisTokenStorage(RedisConnectionFactory factory) {
        return new RedisTokenStorage(factory);
    }

    /**
     * 内存存储实现（默认开发环境使用）
     */
    @Bean
    @ConditionalOnProperty(name = "wx.mp.config-storage.type", havingValue = "memory", matchIfMissing = true)
    public TokenStorage memoryTokenStorage() {
        return new DefaultMemoryTokenStorage();
    }

    /**
     * Redis 存储实现类
     */
    public static class RedisTokenStorage implements TokenStorage {
        private static final String REDIS_KEY = "wx:access_token";
        private final RedisTemplate<String, String> redisTemplate;

        public RedisTokenStorage(RedisConnectionFactory factory) {
            this.redisTemplate = new RedisTemplate<>();
            this.redisTemplate.setConnectionFactory(factory);
            this.redisTemplate.setKeySerializer(new StringRedisSerializer());
            this.redisTemplate.afterPropertiesSet();
        }

        @Override
        public String getToken(boolean forceRefresh) {
            if (forceRefresh) {
                redisTemplate.delete(REDIS_KEY);
                return null;
            }
            return redisTemplate.opsForValue().get(REDIS_KEY);
        }

        @Override
        public void storeToken(String token, int expiresIn) {
            // 提前5分钟过期避免临界点问题
            int ttl = Math.max(expiresIn - 300, 1); // 确保不小于1秒
            redisTemplate.opsForValue().set(
                    REDIS_KEY,
                    token,
                    ttl,
                    TimeUnit.SECONDS
            );
        }
    }

    /**
     * 内存存储实现类
     */
    public static class DefaultMemoryTokenStorage implements TokenStorage {
        private String token;
        private long expireTime;

        @Override
        public synchronized String getToken(boolean forceRefresh) {
            return System.currentTimeMillis() < expireTime ? token : null;
        }

        @Override
        public synchronized void storeToken(String token, int expiresIn) {
            this.token = token;
            this.expireTime = System.currentTimeMillis() + ((expiresIn - 60) * 1000L);
        }
    }

}
